//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/////////////////                                                    /////////////////////
/////////////////        DRAWING CODE - DON'T WORRY ABOUT THIS       /////////////////////
/////////////////                                                    /////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

function drawStroke(lineWidth, points, color) {

  var tris = getStrokeGeometry(points, {
    width: lineWidth,
    cap: lineCap,
    join: lineJoin,
    miterLimit: miterLimit
  });

  // every 3 points, is a tri
  ctx.strokeStyle = color;
  for (var i = 0; i < tris.length; i += 3) {
    ctx.beginPath();
    ctx.moveTo(tris[i].x, tris[i].y);
    ctx.lineTo(tris[i + 1].x, tris[i + 1].y);
    ctx.lineTo(tris[i + 2].x, tris[i + 2].y);
    ctx.closePath();

    ctx.stroke();
  }

  // draw points.
  for (var i = 0; i < points.length; i++) {
    ctx.fillStyle = "red";
    ctx.beginPath();
    ctx.arc(points[i].x, points[i].y, 10, 0, 2 * Math.PI, false);
    ctx.fill();
  }



}

var lineCap = "butt";
var lineJoin = "round";
var lines = true;
var miterLimit = 10;
var drawWithCanvas = true;
var lineWidth = 80;
var points = [
  new Point(500, 100),
  new Point(100, 300),
  new Point(400, 500)
];

var canvas = document.getElementById("c");
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext("2d");

function drawLine(p0, p1, color, width) {
  if (!lines) {
    return;
  }

  ctx.save();
  ctx.translate(p0.x, p0.y);
  ctx.rotate(-Point.Angle(p0, p1));

  var len = Point.Sub(p0, p1).length();

  ctx.lineWidth = width;
  ctx.strokeStyle = color;
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(0, len);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(0, len);
  ctx.lineTo(-5, len - 10);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(0, len);
  ctx.lineTo(5, len - 10);
  ctx.stroke();

  ctx.restore();
}

function drawCrossingLine(_p0, _p1, t1, color, width) {

  if (!lines) {
    return;
  }

  var p0 = Point.Add(_p0, t1);
  var p1 = Point.Add(_p1, t1);
  var pdif = Point.Sub(p1, p0).normalize();
  ctx.save();
  ctx.beginPath();
  ctx.lineWidth = width;
  ctx.strokeStyle = color;
  ctx.moveTo(p0.x - 1000 * pdif.x, p0.y - 1000 * pdif.y);
  ctx.lineTo(p0.x + 1000 * pdif.x, p0.y + 1000 * pdif.y);
  ctx.stroke();
  ctx.restore();
}

function drawInfo() {
  drawLine(points[0], points[1], "#00f", 4);
  drawLine(points[1], points[2], "#00f", 4);

  var t1 = Point.Sub(points[1], points[0]).perpendicular().normalize().scalarMult(lineWidth / 2);
  var t2 = Point.Sub(points[2], points[1]).perpendicular().normalize().scalarMult(lineWidth / 2);
  if (signedArea(points[0], points[1], points[2]) > 0) {
    t1.scalarMult(-1);
    t2.scalarMult(-1);
  }

  if (sizePoints === null) {
    sizePoints = [
      { point: new Point(), reference: points[0] },
      { point: new Point(), reference: points[0] },
      { point: new Point(), reference: points[1] },
      { point: new Point(), reference: points[1] },
      { point: new Point(), reference: points[2] },
      { point: new Point(), reference: points[2] }
    ];
  }

  var p;
  drawLine(points[0], p = Point.Add(points[0], t1), "#0f0", 2);
  sizePoints[0].point.x = p.x;
  sizePoints[0].point.y = p.y;
  drawLine(points[0], p = Point.Sub(points[0], t1), "#070", 2);
  sizePoints[1].point.x = p.x;
  sizePoints[1].point.y = p.y;
  drawLine(points[1], p = Point.Add(points[1], t1), "#0f0", 2);
  sizePoints[2].point.x = p.x;
  sizePoints[2].point.y = p.y;

  drawLine(points[1], p = Point.Add(points[1], t2), "#0f0", 2);
  sizePoints[3].point.x = p.x;
  sizePoints[3].point.y = p.y;
  drawLine(points[2], p = Point.Add(points[2], t2), "#0f0", 2);
  sizePoints[4].point.x = p.x;
  sizePoints[4].point.y = p.y;
  drawLine(points[2], p = Point.Sub(points[2], t2), "#070", 2);
  sizePoints[5].point.x = p.x;
  sizePoints[5].point.y = p.y;


  // from p0+t1 to p1+t1, draw a line.

  drawCrossingLine(points[0], points[1], t1, "#f00", 3);
  drawCrossingLine(points[1], points[2], t2, "#f00", 3);

  var pintersect = lineIntersection(
    Point.Add(t1, points[0]), Point.Add(t1, points[1]),
    Point.Add(t2, points[2]), Point.Add(t2, points[1]));

  if (pintersect && lines) {

    var anchor = null;
    var anchorLength = Number.MAX_VALUE;
    anchor = Point.Sub(pintersect, points[1]);
    anchorLength = anchor.length();

    var p0p1 = Point.Sub(points[0], points[1]);
    var p0p1Length = p0p1.length();
    var p1p2 = Point.Sub(points[1], points[2]);
    var p1p2Length = p1p2.length();

    /**
     * the cross point exceeds any of the segments dimension.
     * do not use cross point as reference.
     */
    if (anchorLength <= p0p1Length && anchorLength <= p1p2Length) {
      ctx.save();
      ctx.fillStyle = "#00f";
      ctx.beginPath();
      ctx.arc(pintersect.x, pintersect.y, 10, 0, 2 * Math.PI, false);
      ctx.fill();
      ctx.restore();

      var pintersect2 = Point.Add(points[1], Point.Sub(points[1], pintersect));
      ctx.save();
      ctx.fillStyle = "#00f";
      ctx.beginPath();
      ctx.arc(pintersect2.x, pintersect2.y, 10, 0, 2 * Math.PI, false);
      ctx.fill();
      ctx.restore();

      drawLine(points[1], pintersect2, "#f0f", 3);
    }
  }

}

function redraw() {
  ctx.fillStyle = "#eee";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  if (drawWithCanvas) {
    ctx.save();
    ctx.beginPath();
    ctx.lineWidth = lineWidth;
    ctx.miterLimit = miterLimit;
    ctx.lineCap = lineCap;
    ctx.lineJoin = lineJoin;
    ctx.moveTo(points[0].x, points[0].y);
    for (var i = 1; i < points.length; i++) {
      ctx.lineTo(points[i].x, points[i].y);
    }
    ctx.strokeStyle = "#ccc";
    ctx.stroke();
    ctx.restore();
  }


  drawStroke(lineWidth, points, "#999");
  drawInfo();
}


var sizePoints = null;

redraw();
